﻿using System;
using System.Linq;
using System.Collections.Generic;
using Citi.Import.Util;
using Citi.GocAttributes.Domain;
using Citi.ResourceConsolidation.Domain.Utils;

namespace Citi.ResourceConsolidation.Domain
{
    public partial class ResourceMonth
    {
        private Goc goc;
        public Goc Goc
        {
            get
            {
                if (goc == null)
                    goc = CacheFacade.Get(() => new Goc().GetGocsByReferenceDate(ReferenceDate).ToList()).FirstOrDefault(x => x.GocAttribute == GocAttributes);

                return goc;
            }
        }

        #region Column Mapping

        private const string GeIdColumn = "GEID";
        private const string GocColumn = "Primary GOC";
        private const string LocalOrgCodeColumn = "Local Org Code";
        private const string BusinessUnitIdColumn = "Bus Unit ID";
        private const string OperatingUnitIdColumn = "Op Unit ID";
        private const string ManagedSegmentIdColumn = "Managed Segment ID";
        //private const string HumanResouceDepartmentIdColumn = "HR Dept ID";
        private const string JobCodeColumn = "Job Code";
        private const string FMBDescriptionColumn = "FMB Desc";
        private const string GlobalFunctionColumn = "Global Function";
        private const string EmployeeClassColumn = "Employee Class";
        private const string FullOrPartTimeColumn = "Full/Part Time";
        private const string RegTempColumn = "Reg / Temp";
        private const string DirectStaffFlagColumn = "Direct Staff Flag";
        private const string DirectStaffCountColumn = "Direct Staff Count";
        private const string FTEColumn = "FTE2";
        private const string FTETypeColumn = "FTE Type";
        private const string TotalHoursColumn = "Total Hours";
        private const string StandardHoursColumn = "Standard Hours";
        private const string WorkingMonthColumn = "Working Month";
        private const string BusinessContactIdColumn = "Business Contact ID";
        private const string VendorIdColumn = "Vendor ID";
        private const string CurrencyColumn = "Currency";
        private const string BillRateColumn = "Bill Rate";
        private const string LocationColumn = "Location";
        private const string CountryOfDomicileColumn = "Country of Domicile";
        private const string ExpenseCodeColumn = "Expense Code";
        private const string OfficerCodeColumn = "Officer Code";
        private const string HRResponsibleGeIdColumn = "HR Responsible GEID";
        private const string DirectManagerGeIdColumn = "Direct Manager GEID";

        private const string HRDeptIdL2Column = "HR Dept ID L2";
        private const string HRDeptIdL3Column = "HR Dept ID L3";
        private const string HRDeptIdL4Column = "HR Dept ID L4";
        private const string HRDeptIdL5Column = "HR Dept ID L5";
        private const string HRDeptIdL6Column = "HR Dept ID L6";
        private const string HRDeptIdL7Column = "HR Dept ID L7";
        private const string HRDeptIdL8Column = "HR Dept ID L8";
        private const string HRDeptIdL9Column = "HR Dept ID L9";

        private const string ManagedGeoIdL2Column = "Managed Geography L2";
        private const string ManagedGeoIdL3Column = "Managed Geography L3";
        private const string ManagedGeoIdL4Column = "Managed Geography L4";
        private const string ManagedGeoIdL5Column = "Managed Geography L5";
        private const string ManagedGeoIdL6Column = "Managed Geography L6";
        private const string ManagedGeoIdL7Column = "Managed Geography L7";
        private const string ManagedGeoIdL8Column = "Managed Geography L8";
        private const string ManagedGeoIdL9Column = "Managed Geography L9";

        #endregion

        #region Column Definitions

        public static readonly List<Definition<ResourceMonth>> GDWDefinitions = new List<Definition<ResourceMonth>>
            {
                new Definition<ResourceMonth> { ModelProperty = x => x.ResourceId, MaxLength = 20, Required = true, ColumnName = GeIdColumn, CustomConversionMethod = ValidateResourceId},
                new Definition<ResourceMonth> { ModelProperty = x => x.LocalCode, MaxLength = 10, Required = true, ColumnName = LocalOrgCodeColumn},
                new Definition<ResourceMonth> { ModelProperty = x => x.GocAttributes, MaxLength = 20, Required = true, ColumnName = GocColumn},
                new Definition<ResourceMonth> { ModelProperty = x => x.BusinessId, Required = true, ColumnName = BusinessUnitIdColumn, CustomConversionMethod = ValidateBusinessUnitId},
                new Definition<ResourceMonth> { ModelProperty = x => x.OperateId, Required = true, ColumnName = OperatingUnitIdColumn, CustomConversionMethod=ValidateOperating},
                //new Definition<ResourceMonth> { ModelProperty = x => x.HumanResourceId,  Required = true, ColumnName = HumanResouceDepartmentIdColumn, CustomConversionMethod = ValidateHumanResource},
                new Definition<ResourceMonth> { ModelProperty = x => x.DomicileCountryId,  Required = true, ColumnName = CountryOfDomicileColumn, CustomConversionMethod = ValidateDomicileCountry},
                new Definition<ResourceMonth> { ModelProperty = x => x.JobTitleId, Required = true, ColumnName = JobCodeColumn, CustomConversionMethod = ValidateJobTitle},
                new Definition<ResourceMonth> { ModelProperty = x => x.FMBDescription, Required = true, ColumnName = FMBDescriptionColumn},
                new Definition<ResourceMonth> { ModelProperty = x => x.GlobalFunction, MaxLength = 10, Required = true, ColumnName = GlobalFunctionColumn},
                new Definition<ResourceMonth> { ModelProperty = x => x.EmployeeClass, Required = true, ColumnName = EmployeeClassColumn, CustomConversionMethod= ValidateEmployeeClass},
                new Definition<ResourceMonth> { ModelProperty = x => x.FullOrPartTime, MaxLength = 1, Required = true, ColumnName = FullOrPartTimeColumn},
                new Definition<ResourceMonth> { ModelProperty = x => x.RegOrTemp, MaxLength = 1, Required = true, ColumnName = RegTempColumn},
                new Definition<ResourceMonth> { ModelProperty = x => x.DirectFlag, MaxLength = 1, Required = true, ColumnName = DirectStaffFlagColumn},
                new Definition<ResourceMonth> { ModelProperty = x => x.DirectCount, MaxLength = 4, Required = true, ColumnName = DirectStaffCountColumn},
                new Definition<ResourceMonth> { ModelProperty = x => x.FTE, Required = true, ColumnName = FTEColumn},
                new Definition<ResourceMonth> { ModelProperty = x => x.FTEType, Required = true, ColumnName = FTETypeColumn},
                new Definition<ResourceMonth> { ModelProperty = x => x.TotalHour, Required = true, ColumnName = TotalHoursColumn},
                new Definition<ResourceMonth> { ModelProperty = x => x.StandardHour, Required = true, ColumnName = StandardHoursColumn},
                new Definition<ResourceMonth> { ModelProperty = x => x.WorkingMonth, Required = true, ColumnName = WorkingMonthColumn, CustomConversionMethod = ValidateWorkMonth},
                new Definition<ResourceMonth> { ModelProperty = x => x.BusinessContactId, Required = true, ColumnName = BusinessContactIdColumn, CustomConversionMethod = ValidateBusinessContactId},
                new Definition<ResourceMonth> { ModelProperty = x => x.VendorId, Required = true, ColumnName = VendorIdColumn, CustomConversionMethod = ValidateVendor},
                new Definition<ResourceMonth> { ModelProperty = x => x.Currency, MaxLength = 10, Required = true, ColumnName = CurrencyColumn},
                new Definition<ResourceMonth> { ModelProperty = x => x.BillRate, Required = true, ColumnName = BillRateColumn},
                new Definition<ResourceMonth> { ModelProperty = x => x.LocationId, Required = true, ColumnName = LocationColumn, CustomConversionMethod=ValidateLocation},
                new Definition<ResourceMonth> { ModelProperty = x => x.ExpenseCode, Required = true, ColumnName = ExpenseCodeColumn },
                new Definition<ResourceMonth> { ModelProperty = x => x.OfficerId, Required = true, ColumnName = OfficerCodeColumn, CustomConversionMethod=ValidateOfficer},
                new Definition<ResourceMonth> { ModelProperty = x => x.HrResponsibleGeId, MaxLength = 10, Required = true, ColumnName = HRResponsibleGeIdColumn},
                new Definition<ResourceMonth> { ModelProperty = x => x.DirectManagerResourceId, Required = true, ColumnName = DirectManagerGeIdColumn, CustomConversionMethod = ValidadeManagerGeID},
                //new Definition<ResourceMonth> { ModelProperty = x => x.HumanResourceDeptId, Required = true, ColumnName = HRDeptIdL9Column, CustomConversionMethod = ValidateHumanResourceDepartment}
                //new Definition<ResourceMonth> { ModelProperty = x => x.ManagedGeographyId, Required = true, ColumnName = ManagedGeoIdL9Column, CustomConversionMethod = ValidateManagedGeography}
            };

        public static readonly List<Definition<ResourceMonth>> MatrixDefinition = new List<Definition<ResourceMonth>>
            {
                new Definition<ResourceMonth> { ModelProperty = x => x.ResourceId, MaxLength = 20, Required = true, ColumnName = GeIdColumn, CustomConversionMethod = ValidateResourceId},
                new Definition<ResourceMonth> { ModelProperty = x => x.DirectManagerResourceId, Required = true, ColumnName = DirectManagerGeIdColumn, CustomConversionMethod = ValidadeManagerGeID},
                new Definition<ResourceMonth> { ModelProperty = x => x.GocAttributes, MaxLength = 20, Required = true, ColumnName = GocColumn},
                new Definition<ResourceMonth> { ModelProperty = x => x.ExpenseCode, Required = true, ColumnName = ExpenseCodeColumn }
                
            };

        #endregion

        #region Custom Validate Method

        private static object ValidateResourceId(ref ResourceMonth model, string value, List<string> fields, ref string error, List<string> headers = null)
        {
            if (string.IsNullOrEmpty(value))
            {
                error = string.Format("The field {0} can not be null", GeIdColumn);
                return Conversion.Validation.Failed;
            }

            var domain = CacheFacade.Get(new Resource().SelectAll<Resource>).FirstOrDefault(x => x.GeId == value);

            if (domain != null)
                model.Resource = domain;
            else
            {
                error = string.Format("The Resource '{0}' was not found", value);
                return Conversion.Validation.Failed;
            }

            return Conversion.Validation.Validated;
        }

        private static object ValidateBusinessUnitId(ref ResourceMonth model, string value, List<string> fields, ref string error, List<string> headers = null)
        {
            if (string.IsNullOrEmpty(value))
            {
                error = string.Format("The field {0} can not be null", BusinessUnitIdColumn);
                return Conversion.Validation.Failed;
            }

            var domain = CacheFacade.Get(new BusinessUnit().SelectAll<BusinessUnit>).FirstOrDefault(x => x.Code == value);

            if (domain != null)
                model.BusinessUnit = domain;
            else
            {
                error = string.Format("The Business Unit '{0}' was not found", value);
                return Conversion.Validation.Failed;
            }

            return Conversion.Validation.Validated;
        }

        private static object ValidateBusinessContactId(ref ResourceMonth model, string value, List<string> fields, ref string error, List<string> headers = null)
        {
            if (string.IsNullOrEmpty(value))
            {
                error = string.Format("The field {0} can not be null", BusinessContactIdColumn);
                return Conversion.Validation.Failed;
            }

            var domain = CacheFacade.Get(new BusinessContact().SelectAll<BusinessContact>).FirstOrDefault(x => x.Code == value);

            if (domain != null)
                model.BusinessContact = domain;
            else
            {
                error = string.Format("The Business Contact '{0}' was not found", value);
                return Conversion.Validation.Failed;
            }

            return Conversion.Validation.Validated;
        }

        private static object ValidateEmployeeClass(ref ResourceMonth model, string value, List<string> fields, ref string error, List<string> headers = null)
        {
            if (string.IsNullOrEmpty(value))
            {
                error = string.Format("The field {0} can not be null", EmployeeClassColumn);
                return Conversion.Validation.Failed;
            }

            var domain = CacheFacade.Get(new EmployeeClass().SelectAll<EmployeeClass>).FirstOrDefault(x => x.Code == value);

            if (domain != null)
                model.EmployeeClass = domain;
            else
            {
                error = string.Format("The EmployeeClass '{0}' was not found", value);
                return Conversion.Validation.Failed;
            }

            return Conversion.Validation.Validated;
        }

        private static object ValidateHumanResource(ref ResourceMonth model, string value, List<string> fields, ref string error, List<string> headers = null)
        {
            if (string.IsNullOrEmpty(value))
            {
                error = string.Format("The field {0} can not be null", "");
                return Conversion.Validation.Failed;
            }

            var domain = CacheFacade.Get(new HumanResource().SelectAll<HumanResource>).FirstOrDefault(x => x.Code == value);

            if (domain != null)
                model.HumanResource = domain;
            else
            {
                error = string.Format("The Human Resource '{0}' was not found", value);
                return Conversion.Validation.Failed;
            }

            return Conversion.Validation.Validated;
        }

        private static object ValidateLocation(ref ResourceMonth model, string value, List<string> fields, ref string error, List<string> headers = null)
        {
            if (string.IsNullOrEmpty(value))
            {
                error = string.Format("The field {0} can not be null", LocationColumn);
                return Conversion.Validation.Failed;
            }

            var domain = CacheFacade.Get(new Location().SelectAll<Location>).FirstOrDefault(x => x.Code == value);

            if (domain != null)
                model.Location = domain;
            else
            {
                error = string.Format("The Location '{0}' was not found", value);
                return Conversion.Validation.Failed;
            }

            return Conversion.Validation.Validated;
        }

        private static object ValidateOfficer(ref ResourceMonth model, string value, List<string> fields, ref string error, List<string> headers = null)
        {
            if (string.IsNullOrEmpty(value))
            {
                error = string.Format("The field {0} can not be null", OfficerCodeColumn);
                return Conversion.Validation.Failed;
            }

            var domain = CacheFacade.Get(new Officer().SelectAll<Officer>).FirstOrDefault(x => x.Code == value);

            if (domain != null)
                model.Officer = domain;
            else
            {
                error = string.Format("The Officer '{0}' was not found", value);
                return Conversion.Validation.Failed;
            }

            return Conversion.Validation.Validated;
        }

        private static object ValidateOperating(ref ResourceMonth model, string value, List<string> fields, ref string error, List<string> headers = null)
        {
            if (string.IsNullOrEmpty(value))
            {
                error = string.Format("The field {0} can not be null", OperatingUnitIdColumn);
                return Conversion.Validation.Failed;
            }

            var domain = CacheFacade.Get(new Operating().SelectAll<Operating>).FirstOrDefault(x => x.Code == value);

            if (domain != null)
                model.Operating = domain;
            else
            {
                error = string.Format("The Operating '{0}' was not found", value);
                return Conversion.Validation.Failed;
            }

            return Conversion.Validation.Validated;
        }

        private static object ValidateVendor(ref ResourceMonth model, string value, List<string> fields, ref string error, List<string> headers = null)
        {
            if (string.IsNullOrEmpty(value))
            {
                error = string.Format("The field {0} can not be null", VendorIdColumn);
                return Conversion.Validation.Failed;
            }

            var domain = CacheFacade.Get(new Vendor().SelectAll<Vendor>).FirstOrDefault(x => x.Code == value);

            if (domain != null)
                model.Vendor = domain;
            else
            {
                error = string.Format("The Vendor '{0}' was not found", value);
                return Conversion.Validation.Failed;
            }

            return Conversion.Validation.Validated;
        }

        private static object ValidateDomicileCountry(ref ResourceMonth model, string value, List<string> fields, ref string error, List<string> headers = null)
        {
            if (string.IsNullOrEmpty(value))
            {
                error = string.Format("The field {0} can not be null", CountryOfDomicileColumn);
                return Conversion.Validation.Failed;
            }

            var domain = CacheFacade.Get(new DomicileCountry().SelectAll<DomicileCountry>).FirstOrDefault(x => x.Description == value);

            if (domain != null)
                model.DomicileCountry = domain;
            else
            {
                error = string.Format("The Location '{0}' was not found", value);
                return Conversion.Validation.Failed;
            }

            return Conversion.Validation.Validated;
        }

        private static object ValidadeManagerGeID(ref ResourceMonth model, string value, List<string> fields, ref string error, List<string> headers = null)
        {
            //if (value.Length > 5)
            //{
            var domain = CacheFacade.Get(new Resource().SelectAll<Resource>).FirstOrDefault(x => x.GeId == value);

            if (domain != null)
                model.DirectManagerResourceId = domain.Id;
            else
                model.DirectManagerResourceId  = model.Resource.Id;
            //}

            //if (value.Length < 5)
            //    model.DirectManagerResourceId = model.ResourceId.Value;


            return Conversion.Validation.Validated;
        }

        private static object ValidateJobTitle(ref ResourceMonth model, string value, List<string> fields, ref string error, List<string> headers = null)
        {
            if (string.IsNullOrEmpty(value))
            {
                error = string.Format("The field {0} can not be null", JobCodeColumn);
                return Conversion.Validation.Failed;
            }

            var domain = CacheFacade.Get(new JobTitle().SelectAll<JobTitle>).FirstOrDefault(x => x.Code == value);

            if (domain != null)
                model.JobTitleId = domain.Id;
            else
            {
                error = string.Format("The Job Title '{0}' was not found", value);
                return Conversion.Validation.Failed;
            }

            return Conversion.Validation.Validated;
        }

        private static object ValidateWorkMonth(ref ResourceMonth model, string value, List<string> fields, ref string error, List<string> headers = null)
        {
            var year = value.Substring(0, 4);
            return new DateTime(int.Parse(year), int.Parse(value.Remove(0, 4)), 1);
        }

        private static object ValidateManagedGeography(ref ResourceMonth model, string value, List<string> fields, ref string error, List<string> headers = null)
        {
            var managedGeographies = new List<string>
                {
                    fields[headers.IndexOf(Conversion.TransformColumnName(ManagedGeoIdL2Column))],
                    fields[headers.IndexOf(Conversion.TransformColumnName(ManagedGeoIdL3Column))],
                    fields[headers.IndexOf(Conversion.TransformColumnName(ManagedGeoIdL4Column))],
                    fields[headers.IndexOf(Conversion.TransformColumnName(ManagedGeoIdL5Column))],
                    fields[headers.IndexOf(Conversion.TransformColumnName(ManagedGeoIdL6Column))],
                    fields[headers.IndexOf(Conversion.TransformColumnName(ManagedGeoIdL7Column))],
                    fields[headers.IndexOf(Conversion.TransformColumnName(ManagedGeoIdL8Column))],
                    fields[headers.IndexOf(Conversion.TransformColumnName(ManagedGeoIdL9Column))]
                };

            var domain = CacheFacade.Get(new ManagedGeography().SelectAll<ManagedGeography>)
                                    .FirstOrDefault(x => x.Id == managedGeographies.Last(y => !string.IsNullOrWhiteSpace(y)));

            if (domain != null)
                model.ManagedGeography = domain;
            else
            {
                error = string.Format("The Managed Geography '{0}' was not found", value);
                return Conversion.Validation.Failed;
            }

            return Conversion.Validation.Validated;
        }

        //private static object ValidateHumanResourceDepartment(ref ResourceMonth model, string value, List<string> fields, ref string error, List<string> headers = null)
        //{
        //    var departments = new List<string>
        //        {
        //            fields[headers.IndexOf(Conversion.TransformColumnName(HRDeptIdL2Column))],
        //            fields[headers.IndexOf(Conversion.TransformColumnName(HRDeptIdL3Column))],
        //            fields[headers.IndexOf(Conversion.TransformColumnName(HRDeptIdL4Column))],
        //            fields[headers.IndexOf(Conversion.TransformColumnName(HRDeptIdL5Column))],
        //            fields[headers.IndexOf(Conversion.TransformColumnName(HRDeptIdL6Column))],
        //            fields[headers.IndexOf(Conversion.TransformColumnName(HRDeptIdL7Column))],
        //            fields[headers.IndexOf(Conversion.TransformColumnName(HRDeptIdL8Column))],
        //            fields[headers.IndexOf(Conversion.TransformColumnName(HRDeptIdL9Column))]
        //        };

        //    var domain = CacheFacade.Get(new HumanResourceDept().SelectAll<HumanResourceDept>)
        //                            .FirstOrDefault(x => x.Id == departments.Last(y => !string.IsNullOrWhiteSpace(y)));

        //    if (domain != null)
        //        model.HumanResourceDept = domain;
        //    else
        //    {
        //        error = string.Format("The Human Resource Department '{0}' was not found", value);
        //        return Conversion.Validation.Failed;
        //    }

        //    return Conversion.Validation.Validated;
        //}

        #endregion

        #region Save Methods

        public static void Save(List<ResourceMonth> resourceMonths)
        {
            if (!resourceMonths.Any()) return;
            resourceMonths.First().Save(resourceMonths, 1200);
            Context.ClearContext();
        }

        #endregion

        public List<ResourceMonth> GetByReferenceDate(DateTime referenceDate)
        {
            return SelectAll<ResourceMonth>().Where(x => x.ReferenceDate == referenceDate).ToList();
        }

        public void MoveResourceMonthToHistory()
        {
            Context.Instance.MoveResourceMonthToHistory();
        }

        public void DeletePreviousData(DateTime referenceDate)
        {
            Context.Instance.DeletePreviousData(referenceDate);
        }
    }
}